﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Threading;

using Model.Items;
using Model.Player;
using Model.Adventure;
using Model.Spells;

using RemotingInterfaces;

namespace Model.Hero
{
    [Serializable]
    public abstract class Character : Race, INotifyPropertyChanged, ICharacter
    {
        protected Object thisLock;        

        protected new String _name;
        protected int _level;
        protected long _XP;
        protected int _current_health;        
        protected List<Feat> _feats;
        protected int _gold;        
        protected int _critical_hit_rating; //like in wow
        //protected double _critical_hit_chance;
        protected List<Buff> _buffs;
        protected List<Debuff> _debuffs;     
        protected Spellbook _spellbook;
        protected IDamage _offensive_damage_stats;
        protected IDamage _defensive_damage_stats;        

        public Character(String race)
            : base(race)
        {
            thisLock = new Object();
            _offensive_damage_stats = new Damage(0);
            _defensive_damage_stats = new Damage(0);
            _buffs = new List<Buff>();
            _debuffs = new List<Debuff>();
            _feats = new List<Feat>();
        }

        public new event PropertyChangedEventHandler PropertyChanged;

        protected void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }

        public new String Name
        {
            get { return _name; }
            set
            {
                _name = value;
                NotifyPropertyChanged("Name");
            }
        }

        public IDamage Offensive_Damage_Stats
        {
            get { return _offensive_damage_stats; }
        }

        public IDamage Defensive_Damage_Stats
        {
            get { return _defensive_damage_stats; }
        }

        public int Critical_Hit_Rating
        {
            get { return _critical_hit_rating; }            
            set
            {
                _critical_hit_rating = value;
            }
        }

        public double Critical_Hit_Chance
        {
            get { return _critical_hit_chance(); }       
        }
            
        private double _critical_hit_chance()
        {
            return 0.05 + (double)_agility / 100 + _critical_hit_rating * 0.5; //should be some measure of agility and critical hit rating
        }

        public bool AddFeat(IFeat feat)
        {
            if (_feats.Contains((Feat)feat))
                return false; //hero already has feat
            _feats.Add((Feat)feat);
            //make sure the feat is ready
            feat.Ready = true;
            return true;
        }

        public IFeat GetFeat(String name)
        {
            return _feats.Find(delegate(Feat f) { return f.Name == name; });
        }

        public List<IFeat> Feats
        {
            get
            {                
                //Cast the list using a converter function
                return _feats.ConvertAll<IFeat>(Feat.IFeat_to_Feat_converter);                
            }
        }

        public void Increment_Cooldown_Counters()
        {
            foreach (Feat feat in _feats)
                feat.Tick();
        }               

        public int CurrentHealth
        {
            get
            {
                lock (thisLock)
                {
                    return _current_health;
                }
            }
            set
            {
                lock (thisLock)
                {
                    //health never gets below 0
                    _current_health = value < 0 ? 0 : value;
                    NotifyPropertyChanged("CurrentHealth");
                }
            }
        }



        public int Level
        {
            get { return _level; }
            set
            {
                _level = value;
                NotifyPropertyChanged("Level");
                //binding til health
            }
        }

        public String GetRace
        {
            get { return base.Name; }
        }

        public override String ToString()
        {
            String str =
                   "Name: " + Name + "\n" +
                   "Race: " + GetRace + "\n" +
                   "Level: " + Level + "\n" +
                   "Strength: " + Strength + "\n" +
                   "Intellect: " + Intellect + "\n" +
                   "Perception: " + Perception + "\n" +
                   "Agility: " + Agility + "\n" +
                   "Vitality: " + Vitality + "\n";
            str += "Feats:\n";
            foreach (Feat f in _feats)
            {
                str += f.Name + "\n";
            }

            return str;
        }
    }
}
